package com.example.documentsearchengine.searcher;
import com.example.documentsearchengine.dao.DocInfo;
import com.example.documentsearchengine.dao.Result;
import com.example.documentsearchengine.dao.Weight;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;

import javax.servlet.annotation.WebServlet;
import java.io.*;
import java.util.*;

public class DocSearcher {
    private String stop_word="D:\\Ddoc_searcher_index\\stop_word.txt";
    private static HashSet<String> hashSet=new HashSet<>();
    private Index index=new Index();
    //进行搜索前需要先将数据填写到文件中
    //.索引⽂件的内容加载到内存中
    public DocSearcher() {
        index.load();
        setStop_word();
    }

    /**
     *用户查询的结果显示
     * @param query 用户输入信息
     * @return 一个有效信息集合类
     */
    public List<Result> search(String query){
        //1.对用户输入的信息进行分词
        List<Term> termList= ToAnalysis.parse(query).getTerms();
        List<Term> terms=new ArrayList<>();
        for(Term term:termList){
            String word=term.getName();
            if(hashSet.contains(word)){
                continue;
            }
            else terms.add(term);
        }

        //对分词在文件中进行搜索
        //2.[触发]对分词进行倒排
        //定义一个全局变量去存储
        List<List<Weight>>lisWeight=new ArrayList<>();
        List<Weight>allTokenRist=new ArrayList<>();
        for(Term term:terms){
            String word=term.getName();
            List<Weight> invertedList=index.getInverted(word);
            if(invertedList==null){
                continue;
            }
            lisWeight.add(invertedList);
        }
        //合并针对多个分词结果查询到相同文档，进行权重合并
       allTokenRist= mergeResult(lisWeight);
        //3.针对结果进行权重排序
        allTokenRist.sort(new Comparator<Weight>() {
            @Override
            public int compare(Weight o1, Weight o2) {
                return o2.getWeight()-o1.getWeight();
            }
        });
        //4.包装结果，去查正牌，构造出查询结果
        List<Result>resultList=new ArrayList<>();
        for(Weight weight:allTokenRist){
            DocInfo docInfo=index.getDocInfo(weight.getDocId());
            Result result=new Result();
            result.setTitle(docInfo.getTitle());
            result.setUrl(docInfo.getUrl());
            result.setDesc(GenDesc(docInfo.getContent(),terms));
            resultList.add(result);
        }
        return resultList;
    }
    public class Pow {
        private int row;
        private int col;

        public Pow(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }
    private List<Weight> mergeResult(List<List<Weight>> lisWeight) {
        //1.针对每一行(id)进行升序排序
        for(List<Weight> weight:lisWeight){
            weight.sort(new Comparator<Weight>() {
                @Override
                public int compare(Weight o1, Weight o2) {
                    return o1.getDocId()- o2.getDocId();
                }
            });
        }
        //2.借助优先级队列。对这些行进行排序
        //target表示目标列表
        List<Weight> target=new ArrayList<>();
        Queue<Pow>queue=new PriorityQueue<>(new Comparator<Pow>() {
            @Override
            public int compare(Pow o1, Pow o2) {
                return lisWeight.get(o1.row).get(o1.col).getDocId()
                        -lisWeight.get(o2.row).get(o2.col).getDocId();
            }
        });
        //初始化队列将,listWeight每行第一个元素加入到队列中
        for (int i = 0; i <lisWeight.size() ; i++) {
            queue.add(new Pow(i,0));
        }
        while (!queue.isEmpty()){
            Pow pow = queue.poll();
            Weight curWeight = lisWeight.get(pow.row).get(pow.col);
            //判断curWeight是否与target.getDocId是相同就相加没有就创建
            if(target.size()>0){
                //取出上一个加入的元素
                Weight lastWight=target.get(target.size()-1);
                if(curWeight.getWeight()==lastWight.getWeight()){
                 lastWight.setWeight(curWeight.getWeight()+lastWight.getWeight());
                }else {
                    //如果不相等就加入到target中
                    target.add(curWeight);
                }
            }else{
                target.add(curWeight);
            }
            Pow newPow=new Pow(pow.row,pow.col+1);
            if(newPow.col>=lisWeight.get(newPow.row).size()){
                continue;
            }
            queue.add(newPow);
        }
        return target;
    }

    private String GenDesc(String content, List<Term> terms) {
        int index=-1;//记录输入词在正文中第一次出现的位置
        for(Term term:terms){
            String word=term.getName();
            //这里的分词需要寻找正文中的单独词  使返回的信息更加准确
            content=content.toLowerCase().replaceAll("\\b"+word+"\\b"," "+word+" ");
            index=content.toLowerCase().indexOf(" "+word+" ");
            if(index<0){
                //该分词没有在正文中出现
                continue;
            }else {
                break;//找到了
            }
        }
        String desc="";
        //标记输入内容的下标
        int descBeg=index<100 ? 0:index-100;
        if(descBeg+200>=content.length()){
            desc=content.substring(descBeg);
        }else {
            desc=content.substring(descBeg,descBeg+200);
        }
        if(index==-1){
            //没有在正文中找到相关信息
            //比较极端 返回前100个字符
            if(desc.length()<100){
                return content.substring(desc.length())+"...";
            }
            return content.substring(0,100)+"...";
        }
        for(Term term:terms){
            //(/?)是不区分大小写
            String word=term.getName();
           desc= desc.replaceAll("(?i)"+" "+ word +" ","<i> "+ word + " </i>" );
        }
        return desc+"...";
    }
    public void setStop_word(){
        try (BufferedReader bufferedReader= new BufferedReader(new FileReader(stop_word))){
            while (true){
                String word=bufferedReader.readLine();
                if(word==null)break;
                hashSet.add(word);
            }
        }  catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        DocSearcher docSearcher = new DocSearcher();
        Scanner scanner = new Scanner(System.in);
//        while (true){
//            System.out.println("->");
//            String word=scanner.next();
//            List<Result> results = docSearcher.search(word);
//            for(Result result:results){
//                System.out.println(result.toString());
           System.out.println(hashSet.size());
    }
    }

